import socket
import msgs
import sys
import logger
import md5
import settings
import hmac
import hashlib


def init():
	if (settings.servFD != None) and (settings.userFD != None) and (settings.confFD != None):
		settings.servFD.close()
		settings.userFD.close()
		settings.confFD.close()

	settings.servFD = open(settings.serverFile, "a+")
	settings.userFD = open(settings.userFile, "a+")
	settings.confFD = open(settings.configFile, "a+")

	confList = settings.confFD.readlines()

	try:
		for item in confList:
			itemList = item.rstrip('\n').split(":")
			key = itemList[0]
			value = itemList[1]
			settings.conf[key] = value
	except IndexError:
		log.write("no entries in config file %s" % (settings.configFile), 1)
	except AttributeError:
		log.write("no entries in server config file %s" % (settings.serverFile), 1)


	servList = settings.servFD.readlines()

	try:
		for item in servList:
			itemList = item.rstrip('\n').split(":")
			key = itemList[0]
			value = itemList[1]
			settings.servers[key] = value
	except IndexError:
		log.write("no entries in server config file %s" % (settings.serverFile), 1)
	except AttributeError:
		log.write("no entries in server config file %s" % (settings.serverFile), 1)

	userList = settings.userFD.readlines()

	try:
		for item in userList:
			itemList = item.rstrip('\n')
			settings.users.append(itemList)
	except IndexError:
		log.write("no users found in %s" % (settings.userFile), 1)
	except AttributeError:
		log.write("no entries in server config file %s" % (settings.serverFile), 1)

	return 0

def validate(conn, data):
	if len(data) > 512 or len(data) == 0:
		return msgs.D_INVALID_DATA

	return msgs.D_VALID_DATA

def getData(conn):
	clnt = str(conn.getpeername()[0])
	port = str(conn.getpeername()[1])
	clnt_context = "%s:%s" % (clnt, port)
	data = ""
	valid = msgs.D_VALID_DATA
	while (1):
		conn_data = conn.recv(1024)
		data += str(conn_data)

		if conn_data == "":
			break

		log.write("valdating data from %s" % (clnt_context), 0)

		valid = validate(conn_data, data)

		if valid == msgs.D_VALID_DATA:
			break

		if valid == msgs.D_INVALID_DATA:
			break

	if (data and (valid == msgs.D_VALID_DATA)):
		return data
	else:
		return None

def handleData(conn, data):
        clnt = str(conn.getpeername()[0])
        port = str(conn.getpeername()[1])
        clnt_context = "%s:%s" % (clnt, port)

	dataLines = data.split("\r\n")

	fn = dataLines[0]
	log.write("%s request from %s" % (fn, clnt_context), 0)
	try:
		func = globals()["%s" % (settings.fns[fn])]
		result = func(conn, data)
		log.write("request from %s completed" % (clnt_context), 1)
	except KeyError:
		log.write("invalid request from %s" % (clnt_context), 1)
	
	return result

def auth(conn, data):
	clnt = conn.getpeername()[0]
	port = conn.getpeername()[1]
	clnt_context = "%s:%s" % (str(clnt), str(port))
	log.write("kinit request from %s" % (clnt_context), 0)

	dataLines = data.split("\r\n")
	hashedUserHashSupplied = dataLines[1].rstrip("\n")

	data = "NULL"
	for entry in settings.servers.values():
		ub = hmac.new(entry)
	        ub.update(hashedUserHashSupplied)
	        hashedUserHashedWithserverKey = ub.hexdigest()

		if hashedUserHashedWithserverKey in settings.users:
			log.write("user authenticated from %s" % (clnt_context), 0)
			auth = 0
			toHash = "%s" % (str(clnt))
			uback = hmac.new(entry)
			uback.update(toHash)
			data = uback.hexdigest()
			break
		else:
			log.write("user authentication failed from %s" % (clnt_context), 1)
			auth = 1


	if (auth == 0):
		conn.setblocking(0)
		while (1):
			try:
				sent = conn.send(data)
			except:
				continue
			break
		conn.setblocking(1)

		return 0
	else:
		return 1	

def crtserver(conn, data):
	if len(data) > 256:
		log.write("too huge server hash", 1)
		return 1

	hostIP = ""
	serverBlob = ""
	try:
		hostIP = data.split("\r\n")[1].split(":")[0]
		serverBlob = data.split("\r\n")[1].split(":")[1]
	except:
		log.write("data not formatted properly", 1)

	entry = "%s:%s\n" % (hostIP, serverBlob)

	settings.servFD.write(entry)
	settings.servFD.flush()
	init()

	return 0
		
def crtuser(conn, data):
	try:
		userBlob = data.split("\r\n")[1]
	except:
		log.write("data not formatted properly", 1)
		return 1

	try:
		servHash = settings.servers[clnt]
	except:
		log.write("server not found in server list", 1)
		return 1

	if not servHash:
		log.write("server doesn not have a corresponding hash in config file", 1)
		return 1

	if len(userBlob) > 250:
		return 1

	try:
		settings.userFD.write("%s\n" %(userBlob))
		settings.userFD.flush()
	except:
		log.write("unable to write to %s" % (settings.userFile), 1)
		return 1

	init()
	return 0


#
# program starts here
#
log = logger.log(settings.logFile)
init()

serv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv_sock.bind(("", 5023))
serv_sock.listen(10)

while (1):
	conn, addr = serv_sock.accept()
	clnt = str(conn.getpeername()[0])
	port = str(conn.getpeername()[1])
	clnt_context = "%s:%s" % (str(clnt), str(port))
	log.write("connection from %s:%s" %(clnt, port), 0)

	data = getData(conn)
	if not data:
		conn.send(msgs.E_INVALID_DATA)
	
	handleData(conn, data)


